# -*- coding: utf-8 -*-
import sys
import socks
import time
import os
import _winreg
import stat

import win32ui
import win32gui
import win32con
import win32api


from paramiko import Transport, Channel, SFTPClient

from PyQt4.QtCore import *
from PyQt4.QtGui import *

from tela import Ui_testerSCP
from telinha import TelaDownload

from downloadar import Downloadar

PASTA = str(QDir.currentPath())
if 'aaaaaa' not in PASTA:
    PASTA += '/aaaaaa'

class TSFTP(QMainWindow):
    def __init__(self, transport=None, parent=None):
        QWidget.__init__(self,parent)

        self.ui = Ui_testerSCP()
        self.ui.setupUi(self)
        
        self.modelo = QFileSystemModel()        
        self.ui.local.setModel(self.modelo)
        self.modelo.setRootPath('.')
        
        self.dir = QDir( QDir.currentPath())
        self.atualizardiretoriolocal()
        
        self.modelo2 = QSFTPModel(transport)
        self.ui.remoto.setModel(self.modelo2)

        self.ui.endlocal.setText(self.dir.currentPath())

        #sinais
        QObject.connect(self.ui.download, SIGNAL("clicked()"), self.downloadfile)
        QObject.connect(self.ui.upload, SIGNAL("clicked()"), self.uploadfile)
        QObject.connect(self.ui.blmkdir, SIGNAL("clicked()"), self.criararpastalocal)
        QObject.connect(self.ui.brmkdir, SIGNAL("clicked()"), self.criararpastaremoto)
        QObject.connect(self.ui.remoto,SIGNAL('doubleClicked(PyQt_PyObject)'), self.doisclicksremoto)
        QObject.connect(self.ui.local,SIGNAL('doubleClicked(PyQt_PyObject)'), self.doisclickslocal)
        QObject.connect(self.ui.bracima,SIGNAL('clicked()'),self.acimaremoto)
        QObject.connect(self.ui.blacima,SIGNAL('clicked()'),self.acimalocal)
        QObject.connect(self.ui.blrename,SIGNAL('clicked()'),self.renamelocal)
        QObject.connect(self.ui.brrename,SIGNAL('clicked()'),self.renameremoto)
        QObject.connect(self.ui.bldeletar,SIGNAL('clicked()'),self.deletarlocal)
        QObject.connect(self.ui.brdeletar,SIGNAL('clicked()'),self.deletarremoto)
        QObject.connect(self.ui.remoto,SIGNAL('f2Pressed()'), self.renameremoto)
        QObject.connect(self.ui.local,SIGNAL('f2Pressed()'), self.renamelocal)
        QObject.connect(self.ui.endremoto,SIGNAL('returnPressed()'),self.mudaendremoto)
        QObject.connect(self.ui.endlocal,SIGNAL('returnPressed()'),self.mudaendlocal)

        QObject.connect(self.modelo2.ssh,SIGNAL('acabou()'),self.acabou)


        self.listadown = []

    ## FiM INIT
    
    def mudaendlocal(self):
        self.dir.setCurrent(str(self.ui.endlocal.text()))
        self.atualizardiretoriolocal()
    
    def mudaendremoto(self):
        self.modelo2.ssh.diretorio=str(self.ui.endremoto.text())
        self.modelo2.listar()
    
    def acabou(self):
        self.ui.endremoto.setText(self.modelo2.ssh.sftp.getcwd())
    
    def deletarlocal(self):
        for item in self.ui.local.selectedIndexes():
            if item.column() == 0:
                try:
                    if self.modelo.isDir(item):
                        self.modelo.rmdir(item)
                    else:
                        self.modelo.remove(item)
                except WindowsError, we:
                    print 'Windows error: ', we
                except Exception, e:
                    print 'EXCEPTION: ', e
            
    def deletarremoto(self):
        for item in self.ui.remoto.selectedIndexes():
            tupla = self.modelo2.data(item,32)
            if tupla:
                try:
                    if tupla[2]:
                        self.modelo2.ssh.sftp.rmdir(self.modelo2.ssh.diretorio+'/'+tupla[0])
                    else:
                        self.modelo2.ssh.sftp.remove(self.modelo2.ssh.diretorio+'/'+tupla[0])
                    self.modelo2.listar()
                except IOError, ioe:
                    print 'IOERROR: ', ioe
                except Exception, e:
                    print 'EXCEPTION: ', e

    def renamelocal(self):
        for item in self.ui.local.selectedIndexes():
            if item.column() == 0:
                nomevelho = str(self.modelo.fileInfo(item).fileName())
                try:
                    novonome = QInputDialog.getText(self, "Nome do arquivo", "Digite o novo nome do arquivo:", QLineEdit.Normal,"")
                    if novonome[1]:
                        self.dir.rename(nomevelho,novonome[0])
                    self.atualizardiretoriolocal()
                except WindowsError, we:
                    print 'IOERROR: ', we
                except Exception, e:
                    print 'EXCEPTION: ', e

    def renameremoto(self):
        for item in self.ui.remoto.selectedIndexes():
            tupla = self.modelo2.data(item,32)
            if tupla:
                try:
                    novonome = QInputDialog.getText(self, "Nome do arquivo", "Digite o novo nome do arquivo:", QLineEdit.Normal,"")
                    if novonome[1]:
                        self.modelo2.ssh.sftp.rename(self.modelo2.ssh.diretorio+'/'+tupla[0],self.modelo2.ssh.diretorio+'/'+str(novonome[0]))
                    self.modelo2.listar()
                except IOError, ioe:
                    print 'IOERROR: ', ioe
                except Exception, e:
                    print 'EXCEPTION: ', e

    def atualizardiretoriolocal(self):
        self.diretoriolocal = self.dir.currentPath()
        self.ui.local.setRootIndex(self.modelo.index(self.diretoriolocal))
        self.ui.endlocal.setText(self.dir.currentPath())

    def acimalocal(self):
        self.dir.setCurrent('..')
        self.atualizardiretoriolocal()

    def acimaremoto(self):
        self.modelo2.ssh.diretorio='..'
        self.modelo2.listar()

    def doisclicksremoto(self, evento):
        for idx in self.ui.remoto.selectedIndexes():
            tupla = self.modelo2.data(idx,32)
            if tupla:
                if tupla[2] == True: #tupla[2] eh um booleano que indica se eh um diretorio ou nao
                    self.modelo2.ssh.diretorio='./'+tupla[0] #download(tupla,self.diretoriolocal,'.')
                    self.modelo2.listar()
        print evento.x()
        print evento.y()

    def doisclickslocal(self):
        for item in self.ui.local.selectedIndexes():
            if item.column() == 0:
                fileinfo = self.modelo.fileInfo(item)
                nome = str(fileinfo.fileName())
                nome = self.diretoriolocal + '/' + nome
                if fileinfo.isDir():
                    self.dir.setCurrent(nome)
                    self.atualizardiretoriolocal()
                else:
                    os.startfile(nome)

    def criararpastalocal(self):
        self.criararpasta(os)

    def criararpastaremoto(self):
        self.criararpasta(self.modelo2.ssh.sftp)
        self.modelo2.listar()

    def criararpasta(self, objeto):
        cont = 0
        while True:
            try:
                nomepasta = "Nova Pasta"
                if cont:
                    nomepasta += '('+str(cont)+')'
                cont += 1
                objeto.mkdir(nomepasta)
                break
            except WindowsError, we:
                print 'pasta existente'
            except IOError, ioe:
                print 'bla bla'
            except Exception, e:
                print "Erro na criacao da pasta:", e
                break

    def downloadfile(self,remoto='.'):
        lista = []
        for idx in self.ui.remoto.selectedIndexes():
            tupla = self.modelo2.data(idx,32)
            if tupla:
                lista.append((tupla,str(self.diretoriolocal)))
        self.downloadtudo(lista,'.')
            
        self.a = TelaDownload(self,self.listadown)
        self.a.show()
        self.modelo2.ssh.download(self.listadown)
        self.connect(self.modelo2.ssh, SIGNAL('chunkGetted(PyQt_PyObject)'), self.a.atualiza )
        self.connect(self.modelo2.ssh, SIGNAL('downloadFinished()'), self.b )
        
    def b(self):
        print 'b'
        self.a.close()
        del self.a
        
    def downloadtudo(self, lista, pai):
        for indice in lista:
            nome = indice[0][0]
            tamanho = indice[0][1]
            isdir = indice[0][2]
            dirloc = indice[1]
            if isdir:
                novopai = pai+'/'+nome
                os.mkdir(novopai)
                novalista = self.listadiretorio(novopai)
                self.downloadtudo(novalista, novopai)
            else:
                self.listadown.append((nome,tamanho,dirloc,pai))

    def listadiretorio(self,diretorio):
        arqs = self.modelo2.ssh.sftp.listdir_attr(diretorio)
        lista = []
        for arquivo in arqs:
            nome = arquivo.filename
            tamanho = arquivo.st_size
            isdir = (stat.S_IFMT(arquivo.st_mode) == stat.S_IFDIR)
            lista.append(((nome, tamanho, isdir),str(self.diretoriolocal)+'/'+diretorio))
        return lista
        
    def uploadfile(self):
        i = 0
        for item in self.ui.local.selectedIndexes():
            if item.column() == 0:
                tupla = (str(self.modelo.fileInfo(item).fileName()),self.modelo.fileInfo(item).size())
                self.modelo2.ssh.upload(tupla,self.diretoriolocal,'.')

def sortbyname(a,b):
    return cmp(a[0],b[0])
    
def strtoint(num):
    if num[-2:] == 'GB':
        return int( num[:-3] ) * 1024 * 1024 * 1024
    elif num[-2:] == 'MB':
        return int( num[:-3] ) * 1024 * 1024
    elif num[-2:] == 'KB':
        return int( num[:-3] ) * 1024
    return int( num[:-6] )
        
    
def sortbysize(a,b):
    n1 = strtoint(a[1])
    n2 = strtoint(b[1])
    return cmp(n1,n2)
    
def sortbytype(a,b):
    arq1, tam1, dia1, isdir1 = a
    ext1 = arq1.split('.')
    arq2, tam2, dia2, isdir2 = b
    ext2 = arq2.split('.')
    if isdir1 and not isdir2:
        return -1
    elif isdir1 and isdir2:
        return cmp(arq1,arq2)
    elif not isdir1 and isdir2:
        return 1
    else:
        if len(ext1)>1 and len(ext2)>1:
            if ext1[-1] == ext2[-1]:
                return cmp(arq1,arq2)
            else:
                return cmp(ext1[-1],ext2[-1])
        else:
            return cmp(arq1,arq2)
    
def sortbydate(a,b):
    date1=time.strptime(a[2],'%d/%m/%Y %H:%M:%S')
    date2=time.strptime(b[2],'%d/%m/%Y %H:%M:%S')
    return cmp(date1,date2)
        
class QSFTPModel(QAbstractTableModel):
    def __init__(self, transport = None, parent=None):
        QAbstractTableModel.__init__(self, parent)
        self.total = 2
        self.ssh = SSH(transport)
        QObject.connect(self.ssh, SIGNAL('acabou()'), self.acabei)
        QObject.connect(self.ssh, SIGNAL('listar()'), self.listar)
        self.column = 0
        self.order = 1


    def acabei(self):
        self.arquivos = self.ssh.arquivos
        for x in self.arquivos:
            arquivo, tamanho, dia, isdir = x
        self.sort(self.column, self.order)
        
    def listar(self):
        self.beginRemoveRows(QModelIndex(), 0,self.rowCount(QModelIndex())-1)
        self.endRemoveRows()
        self.ssh.listar=True
        
    def insertRow(self, pos, parent = QModelIndex()):
        self.beginInsertRows(parent, 0, 0)
        self.endInsertRows()
        

    def insertRows(self, pos, count, parent=QModelIndex()):
        for i in xrange(count):
            self.insertRow(0)
            
    def sort(self, column, order):
        try:
            if column == 0:
                self.arquivos.sort(sortbyname)
                if order == 1:
                    self.arquivos.reverse()
            elif column == 1:
                self.arquivos.sort(sortbysize)
                if order == 1:
                    self.arquivos.reverse()
            elif column == 2:
                self.arquivos.sort(sortbytype)
                if order == 1:
                    self.arquivos.reverse()
            elif column == 3:
                self.arquivos.sort(sortbydate)
                if order == 1:
                    self.arquivos.reverse()
            self.column = column
            self.order = order
            self.beginRemoveRows(QModelIndex(), 0,self.rowCount(QModelIndex())-1)
            self.endRemoveRows()
            self.insertRows(0, len(self.arquivos))
        except:
            pass
    def headerData(self,section, orientation, role):
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                if section == 0:
                    return QVariant('Name')
                elif section == 1:
                    return QVariant('Size')
                elif section == 2:
                    return QVariant('Type')
                elif section == 3:
                    return QVariant('Date Modified')
        return QVariant()
        
    def index(self, row, column, parent = QModelIndex()):
        if row < self.ssh.tamanho:
            return self.createIndex(row,column)
        return QModelIndex()
            
    def parent(self, index):
        return QModelIndex()
        
    def rowCount(self, parent):
        if not parent.isValid():
            return self.ssh.tamanho
        return 0
        
    def columnCount(self, parent):
        if not parent.isValid():
            return 4
        return 0
        
    def data(self, index, role=None):
        if not index.isValid():
            return QVariant()
                
        if role == 32:
            if index.column() == 0:
                arquivo, tamanho, dia, isdir = self.arquivos[index.row()]
                return (arquivo,tamanho, isdir)
            else:
                return None

        if role == Qt.DisplayRole:
            if self.arquivos[index.row()]:
                arquivo, tamanho, dia, isdir = self.arquivos[index.row()]
                extension = arquivo.split('.')
                if index.column() == 0:
                    return QVariant(arquivo)
                elif index.column() == 1:
                    return QVariant(inttostring(tamanho))
                elif index.column() == 2:
                    if isdir:
                        return QVariant('File folder')
                    else:
                        if len(extension)>1:
                            return QVariant(extension[-1]+' File')
                        else:
                            return QVariant('File')
                elif index.column() == 3:
                    return QVariant(dia)
            else:
                return QVariant()
        elif role == Qt.DecorationRole:
            arquivo, tamanho, dia, isdir = self.arquivos[index.row()]
            if index.column() == 0:
                if isdir:
                    return QVariant(QIcon(PASTA+'/folder.png'))
                else:
                    return QVariant(QIcon(PASTA+'/file.png'))
                return QVariant(QIcon('caminhao.png'))
        elif role == Qt.TextAlignmentRole:
            if index.column() == 0:
                return QVariant(Qt.AlignLeft)
            elif index.column() == 1:
                return QVariant(Qt.AlignRight)
            elif index.column() == 2:
                return QVariant(Qt.AlignLeft)
            elif index.column() == 3:
                return QVariant(Qt.AlignLeft)
        else:
            return QVariant()
        return QVariant()
        
class SSH(QThread):
    def __init__(self, transport = None):
        QThread.__init__(self)
        self.tamanho = 0
        self.listar = True
        self.downloadar = False
        self.uploadar = False
        self.diretorio = '.'
        self.downloadando = False
        if not transport:
            self.sock = socks.socksocket()
            self.sock.settimeout(10)
            self.sock.connect( ('189.19.92.68',22) )
            self.transport = Transport(self.sock)
            self.transport.set_keepalive(60)
            self.transport.connect(username='guenka2',password='continental')
            self.chann = self.transport.open_session()
        else:
            self.transport = transport
        self.sftp = SFTPClient.from_transport(self.transport)
        self.start()
        
    def run(self):
        try:
            while True:
                time.sleep(0.1)
                if self.listar:
                    self.list()
                    self.diretorio = '.'
                elif self.uploadar:
                    self.uploadar = False
                    self.sftp.put(self.diretoriolocal+'/'+self.trupa[0], self.diretorioremoto+'/'+self.trupa[0])
                    self.emit(SIGNAL('listar()'))
        except Exception, e:
            print e

    def download(self, lista): # trupa, diretoriolocal, diretorioremoto):
        if not self.downloadando:
            self.downloadando = True
            self.listadownloads = lista
            self.contador = 0
            self.downloadproximo()

    def downloadproximo(self):
        if self.listadownloads:
            self.contador+=1
            elemento = self.listadownloads.pop(0)
            nomearquivo = elemento[0]
            tamanhoarquivo = elemento[1]
            dirloc = elemento[2]
            dirrem = elemento[3]
            self.d = Downloadar(self.sftp,nomearquivo, dirloc, dirrem)
            self.connect(self.d,SIGNAL('down_finished()'), self.downloadproximo)
            self.connect(self.d,SIGNAL('chunkGetted(PyQt_PyObject)'), self.chunkdodownload)
        else:
            #ACABOU OS DOWNLOADS
            self.downloadando = False
            self.emit(SIGNAL('downloadFinished()'))
            
    def chunkdodownload(self, tupra):
        self.emit(SIGNAL('chunkGetted(PyQt_PyObject)'), (tupra[0],tupra[1], self.contador) )

    def upload(self, trupa, diretoriolocal, diretorioremoto):
        self.trupa = trupa
        self.diretoriolocal = diretoriolocal
        self.diretorioremoto = diretorioremoto
        self.uploadar = True
        # self.sftp.put(diretoriolocal+'/'+trupa[0], diretorioremoto+'/'+trupa[0])

    def list(self):
        self.listar = False
        try:
            self.sftp.chdir(self.diretorio)
        except Exception, e:
            print e
        try:
            arquivos = self.sftp.listdir_attr()
            self.arquivos = []
            for item in arquivos:
                if (item.st_mtime is None) or (item.st_mtime == 0xffffffff): 
                      datestr = '(unknown date)' 
                else: 
                    datestr = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(item.st_mtime)) 
                kind = stat.S_IFMT(item.st_mode) #tipo do arquivo
                self.arquivos.append( (item.filename, item.st_size, datestr, (kind == stat.S_IFDIR)) )
            self.tamanho = len(self.arquivos)
            self.emit(SIGNAL('acabou()'))
        except Exception, e:
            self.sftp.chdir('..')
            self.listar = True
            print e
            
def inttostring(lalala):
    sizestr = str(lalala) + ' bytes'
    if lalala>1024:
        sizestr = str(lalala/1024) + ' KB'
        if lalala>(1024*1024):
            sizestr = str(lalala/(1024*1024)) + ' MB'
            if lalala>(1024*1024*1024):
                sizestr = str(lalala/(1024*1024*1024)) + ' GB'
    return sizestr
            
if __name__ == '__main__':
    # getDefaultIcon('a.txt')
    # getDefaultIcon('a.exe')
    # getDefaultIcon('a.jpg')
    # getDefaultIcon('a.mp3')
    app = QApplication(sys.argv)
    myapp = TSFTP()
    myapp.show()
    sys.exit(app.exec_())
    
